home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / microtym.zip / TIMING.ASM
Assembly Source File  |  1991-03-18  |  4KB  |  104 lines

  1. /*
  2. **  Contains routines to perform microsecond accuracy timing
  3. **  operations.
  4. **
  5. **  Adapted from public domain sources
  6. */
  7.  
  8. #include "uclock.h"
  9.  
  10. /* Constants */
  11.  
  12. #define CONTVAL   0x34    /* == 00110100 Control byte for 8253 timer.   */
  13.                           /* Sets timer 0 to 2-byte read/write,         */
  14.                           /* mode 2, binary.                            */
  15. #define T0DATA    0x40    /* Timer 0 data port address.                 */
  16. #define TMODE     0x43    /* Timer mode port address.                   */
  17. #define BIOS_DS   0x40    /* BIOS data segment.                         */
  18. #define B_TIKP    0x6c    /* Address of BIOS (18.2/s) tick count.       */
  19. #define SCALE    10000    /* Scale factor for timer ticks.              */
  20.  
  21. /* The following values assume 18.2 BIOS ticks per second resulting from
  22.    the 8253 being clocked at 1.19 MHz. */
  23.  
  24. #define us_BTIK  54925    /* Micro sec per BIOS clock tick.             */
  25. #define f_BTIK    4595    /* Fractional part of usec per BIOS tick.     */
  26. #define us_TTIK   8381    /* Usec per timer tick * SCALE. (4/4.77 MHz)  */
  27.  
  28. static int init = 0;
  29.  
  30. /*
  31. **  usec_clock()
  32. **
  33. **  An analog of the clock() function, usec_clock() returns a number of
  34. **  type uclock_t (defined in RBS.H) which represents the number of
  35. **  microseconds past midnight. Analogous to CLK_TCK is UCLK_TCK, the
  36. **  number which a usec_clock() reading must be divided by to yield
  37. **  a number of seconds.
  38. */
  39.  
  40. uclock_t usec_clock(void)
  41. {
  42.         unsigned char msb, lsb;
  43.         unsigned int tim_ticks;
  44.         static uclock_t last, init_count;
  45.         static uclock_t far *c_ptr;
  46.         uclock_t count, us_tmp;
  47.  
  48.         if (!init)
  49.         {
  50.                 c_ptr = (uclock_t far *)MK_FP(BIOS_DS, B_TIKP);
  51.                 init  = 1;     /* First call, we have to set up timer.  */
  52.                 int_off();
  53.                 outp(TMODE, CONTVAL);   /* Write new control byte.      */
  54.                 outp(T0DATA, 0);        /* Initial count = 65636.       */
  55.                 outp(T0DATA, 0);
  56.                 init_count = *c_ptr;
  57.                 int_on();
  58.                 return 0;                   /* First call returns zero. */
  59.         }
  60.  
  61.         /* Read PIT channel 0 count - see text                          */
  62.  
  63.         int_off();    /* Don't want an interrupt while getting time.    */
  64.         outp(TMODE, 0);                         /* Latch count.         */
  65.         lsb = (unsigned char)inp(T0DATA);       /* Read count.          */
  66.         msb = (unsigned char)inp(T0DATA);
  67.  
  68.         /* Get BIOS tick count (read BIOS ram directly for speed and
  69.            to avoid turning on interrupts).                             */
  70.  
  71.         count =  *c_ptr;
  72.         int_on();                           /* Interrupts back on.      */
  73.         if ((-1) == init)                   /* Restart count            */
  74.         {
  75.                 init_count = count;
  76.                 init = 1;
  77.         }
  78.  
  79.         /* Merge PIT channel 0 count with BIOS tick count               */
  80.  
  81.         if (count < init_count)
  82.                 count += last;
  83.         else    last = count;
  84.         count -= init_count;
  85.         tim_ticks = (unsigned)(-1) - ((msb << 8) | lsb);
  86.         us_tmp    = count * us_BTIK;
  87.         return (us_tmp + ((long)tim_ticks * us_TTIK + us_tmp % SCALE) / SCALE);
  88. }
  89.  
  90. /*
  91. **  restart_uclock()
  92. **
  93. **  Since usec_clock() bases its return value on a differential value,
  94. **  a potential exists for problems in programs which run continuously
  95. **  for more than 24 hours. In such an application, it's necessary, at
  96. **  least once a day, to reset usec_clock's starting count.
  97. */
  98.  
  99. void restart_uclock(void)
  100. {
  101.         if (init)
  102.                 init = -1;
  103. }
  104.